import {
  BaseSearchProp,
  BaseSearchResult,
  DataSearchProp,
  DataSearchResult,
  ElasticsearchClientProp,
  SeniorSearchProp
} from "../types";
import { ElasticsearchClientCommon } from "../abs/ElasticsearchClientCommon";

export class ElasticsearchClientV7 extends ElasticsearchClientCommon {
  constructor(props: ElasticsearchClientProp) {
    super(props, 7);
  }

  // ---------------------------------------- 索引操作 ----------------------------------------
  async createIndex(data: string): Promise<void> {
    try {
      // 解析索引配置数据
      const indexConfig = JSON.parse(data);

      // 提取索引名称
      let indexName: string;
      let indexBody: any;

      if (typeof indexConfig === "object" && indexConfig !== null) {
        // 如果数据包含索引名称
        if (indexConfig.index) {
          indexName = indexConfig.index;
          indexBody = { ...indexConfig };
          delete indexBody.index;
        } else if (Object.keys(indexConfig).length === 1) {
          // 如果数据是 { "index_name": { settings, mappings } } 格式
          indexName = Object.keys(indexConfig)[0];
          indexBody = indexConfig[indexName];
        } else {
          // 默认情况，需要从外部指定索引名称
          return Promise.reject(
            new Error(
              '索引配置中缺少索引名称，请在配置中指定 "index" 字段或使用 {"index_name": {...}} 格式'
            )
          );
        }
      } else {
        return Promise.reject(new Error("无效的索引配置格式"));
      }

      // 发送创建索引请求
      await this.request({
        method: "PUT",
        url: `/${indexName}`,
        data: JSON.stringify(indexBody)
      });
    } catch (error) {
      if (error instanceof SyntaxError) {
        throw new Error(`索引配置JSON格式错误: ${error.message}`);
      }
      throw new Error(`创建索引失败: ${error}`);
    }
  }

  async deleteBatchIndex(indexIds: Array<string>): Promise<void> {
    try {
      if (!indexIds || indexIds.length === 0) {
        return Promise.reject(new Error("索引ID列表不能为空"));
      }

      // 构建批量删除的索引名称字符串
      const indexNames = indexIds.join(",");

      // 发送删除请求
      await this.request({
        method: "DELETE",
        url: `/${indexNames}`
      });
    } catch (error) {
      throw new Error(`批量删除索引失败: ${error}`);
    }
  }

  async updateIndex(index: string, data: string): Promise<void> {
    try {
      // 解析更新配置数据
      const updateConfig = JSON.parse(data);

      // 在Elasticsearch 7.x中，索引创建后某些设置不能直接修改
      // 我们需要分别处理settings和mappings的更新

      if (updateConfig.settings) {
        // 更新索引设置（只能更新动态设置）
        await this.request({
          method: "PUT",
          url: `/${index}/_settings`,
          data: JSON.stringify({ settings: updateConfig.settings })
        });
      }

      if (updateConfig.mappings) {
        // 更新映射（在ES 7.x中，只能添加新字段，不能修改现有字段类型）
        await this.request({
          method: "PUT",
          url: `/${index}/_mapping`,
          data: JSON.stringify(updateConfig.mappings)
        });
      }

      // 如果只是普通的映射更新
      if (!updateConfig.settings && !updateConfig.mappings && updateConfig.properties) {
        await this.request({
          method: "PUT",
          url: `/${index}/_mapping`,
          data: JSON.stringify({ properties: updateConfig.properties })
        });
      }

      // 如果是完整的映射结构
      if (!updateConfig.settings && !updateConfig.mappings && !updateConfig.properties) {
        await this.request({
          method: "PUT",
          url: `/${index}/_mapping`,
          data: data
        });
      }
    } catch (error) {
      if (error instanceof SyntaxError) {
        throw new Error(`索引更新配置JSON格式错误: ${error.message}`);
      }
      throw new Error(`更新索引失败: ${error}`);
    }
  }

  // ---------------------------------------- 文档操作 ----------------------------------------

  async insertDoc(index: string, data: string): Promise<string> {
    try {
      // 解析文档数据
      const docData = JSON.parse(data);

      // 检查是否指定了文档ID
      let docId: string | undefined;
      let docBody: any = docData;

      if (docData._id) {
        docId = docData._id;
        docBody = { ...docData };
        delete docBody._id;
      }

      // 构建请求URL
      let url = `/${index}/_doc`;
      if (docId) {
        url = `/${index}/_doc/${docId}`;
      }

      // 发送插入请求
      const response = await this.request({
        method: "POST",
        url: url,
        data: JSON.stringify(docBody)
      });

      const result = JSON.parse(response);

      // 返回文档ID
      return result._id || "";
    } catch (error) {
      if (error instanceof SyntaxError) {
        throw new Error(`文档数据JSON格式错误: ${error.message}`);
      }
      throw new Error(`插入文档失败: ${error}`);
    }
  }

  async updateDoc(index: string, id: string, data: string): Promise<void> {
    try {
      // 解析更新数据
      const updateData = JSON.parse(data);

      // 构建更新请求体
      const updateBody = {
        doc: updateData
      };

      // 发送更新请求
      await this.request({
        method: "POST",
        url: `/${index}/_update/${id}`,
        data: JSON.stringify(updateBody)
      });
    } catch (error) {
      if (error instanceof SyntaxError) {
        throw new Error(`更新数据JSON格式错误: ${error.message}`);
      }
      throw new Error(`更新文档失败: ${error}`);
    }
  }

  async deleteBatchDoc(index: string, docIds: Array<string>): Promise<void> {
    try {
      if (!docIds || docIds.length === 0) {
        return Promise.reject(new Error("文档ID列表不能为空"));
      }

      // 构建批量删除请求体
      const bulkBody: string[] = [];

      docIds.forEach((docId) => {
        bulkBody.push(
          JSON.stringify({
            delete: {
              _index: index,
              _id: docId
            }
          })
        );
      });

      // 添加换行符结尾（Elasticsearch bulk API要求）
      const bulkData = bulkBody.join("\n") + "\n";

      // 发送批量删除请求
      const response = await this.request({
        method: "POST",
        url: "/_bulk",
        data: bulkData,
        headers: {
          "Content-Type": "application/x-ndjson"
        }
      });

      // 检查响应中是否有错误
      const result = JSON.parse(response);
      if (result.errors) {
        const errorItems = result.items.filter((item: any) => item.delete && item.delete.error);
        if (errorItems.length > 0) {
          return Promise.reject(new Error(`批量删除部分失败: ${JSON.stringify(errorItems)}`));
        }
      }
    } catch (error) {
      return Promise.reject(new Error(`批量删除文档失败: ${error}`));
    }
  }

  // ---------------------------------------- 搜索操作 ----------------------------------------

  // 辅助方法：扁平化对象
  private flattenObject(obj: any, prefix = ""): Record<string, any> {
    const flattened: Record<string, any> = {};

    Object.keys(obj).forEach((key) => {
      const fullKey = prefix ? `${prefix}.${key}` : key;
      if (obj[key] && typeof obj[key] === "object" && !Array.isArray(obj[key])) {
        Object.assign(flattened, this.flattenObject(obj[key], fullKey));
      } else {
        flattened[fullKey] = obj[key];
      }
    });

    return flattened;
  }

  async dataSearch(props: DataSearchProp): Promise<DataSearchResult> {
    const { must, should, mustNot, order, index, pageNum, pageSize } = props;

    // 构建bool查询
    const boolQuery: any = {
      bool: {}
    };

    // 构建查询条件
    const buildQueryClause = (item: any) => {
      const { field, operator, value, valueType } = item;
      let actualValue: any = value;

      // 根据值类型转换
      if (valueType === "number") {
        actualValue = Number(value);
      } else if (valueType === "boolean") {
        actualValue = value === "true";
      }

      switch (operator) {
        case "eq":
          return { term: { [field]: actualValue } };
        case "ne":
          return { bool: { must_not: { term: { [field]: actualValue } } } };
        case "gt":
          return { range: { [field]: { gt: actualValue } } };
        case "gte":
          return { range: { [field]: { gte: actualValue } } };
        case "lt":
          return { range: { [field]: { lt: actualValue } } };
        case "lte":
          return { range: { [field]: { lte: actualValue } } };
        case "like":
          return { wildcard: { [field]: `*${value}*` } };
        case "match":
          return { match: { [field]: value } };
        case "exists":
          return { exists: { field } };
        case "missing":
          return { bool: { must_not: { exists: { field } } } };
        case "in": {
          const values = value.split(",").map((v: string) => v.trim());
          return { terms: { [field]: values } };
        }
        default:
          return { term: { [field]: actualValue } };
      }
    };

    // 构建must查询
    if (must.length > 0) {
      boolQuery.bool.must = must.map(buildQueryClause);
    }

    // 构建should查询
    if (should.length > 0) {
      boolQuery.bool.should = should.map(buildQueryClause);
    }

    // 构建must_not查询
    if (mustNot.length > 0) {
      boolQuery.bool.must_not = mustNot.map(buildQueryClause);
    }

    // 构建排序
    const sort: any[] = [];
    order.forEach((item) => {
      sort.push({ [item.field]: { order: item.operator } });
    });

    // 构建搜索请求体
    const searchBody: any = {
      query: Object.keys(boolQuery.bool).length > 0 ? boolQuery : { match_all: {} },
      from: (pageNum - 1) * pageSize,
      size: pageSize,
      _source: true
    };

    if (sort.length > 0) {
      searchBody.sort = sort;
    }

    try {
      const response = await this.request({
        method: "POST",
        url: `/${index}/_search`,
        data: JSON.stringify(searchBody)
      });

      const result = JSON.parse(response);
      const hits = result.hits.hits || [];

      // 提取所有字段名
      const allFields = new Set<string>();
      hits.forEach((hit: any) => {
        if (hit._source) {
          const extractFields = (obj: any, prefix = "") => {
            Object.keys(obj).forEach((key) => {
              const fullKey = prefix ? `${prefix}.${key}` : key;
              if (obj[key] && typeof obj[key] === "object" && !Array.isArray(obj[key])) {
                extractFields(obj[key], fullKey);
              } else {
                allFields.add(fullKey);
              }
            });
          };
          extractFields(hit._source);
        }
      });

      // 构建列配置
      const columns = Array.from(allFields).map((field) => ({
        field,
        title: field,
        width: 150,
        ellipsis: true,
        cellClass: "",
        show: true,
        sortable: {
          sortDirections: ["ascend", "descend"] as ("ascend" | "descend")[]
        }
      }));

      // 构建记录数据
      const records = hits.map((hit: any) => ({
        _id: hit._id,
        _index: hit._index,
        _type: hit._type,
        _score: hit._score,
        _source: JSON.stringify(hit._source, null, 2),
        ...this.flattenObject(hit._source)
      }));

      return {
        columns,
        records,
        total: result.hits.total.value || result.hits.total,
        source: response
      };
    } catch (error) {
      throw new Error(`数据搜索失败: ${error}`);
    }
  }

  async baseSearch(props: BaseSearchProp): Promise<BaseSearchResult> {
    const { query, order, index, pageNum, pageSize } = props;

    // 构建bool查询
    const boolQuery: any = {
      bool: {}
    };

    // 分组查询条件
    const mustQueries: any[] = [];
    const shouldQueries: any[] = [];
    const mustNotQueries: any[] = [];

    query
      .filter((item) => item.isEnable)
      .forEach((item) => {
        let queryClause: any = {};

        switch (item.condition) {
          case "match":
            queryClause = { match: { [item.field]: item.value } };
            break;
          case "term":
            queryClause = { term: { [item.field]: item.value } };
            break;
          case "terms":
            queryClause = { terms: { [item.field]: item.value.split(",").map((v) => v.trim()) } };
            break;
          case "exists":
            queryClause = { exists: { field: item.field } };
            break;
          case "missing":
            queryClause = { bool: { must_not: { exists: { field: item.field } } } };
            break;
          case "wildcard":
            queryClause = { wildcard: { [item.field]: item.value } };
            break;
          case "range_lt":
            queryClause = { range: { [item.field]: { lt: item.value } } };
            break;
          case "range_lte":
            queryClause = { range: { [item.field]: { lte: item.value } } };
            break;
          case "range_gt":
            queryClause = { range: { [item.field]: { gt: item.value } } };
            break;
          case "range_gte":
            queryClause = { range: { [item.field]: { gte: item.value } } };
            break;
        }

        switch (item.type) {
          case "must":
            mustQueries.push(queryClause);
            break;
          case "should":
            shouldQueries.push(queryClause);
            break;
          case "must_not":
            mustNotQueries.push(queryClause);
            break;
        }
      });

    // 设置bool查询条件
    if (mustQueries.length > 0) boolQuery.bool.must = mustQueries;
    if (shouldQueries.length > 0) boolQuery.bool.should = shouldQueries;
    if (mustNotQueries.length > 0) boolQuery.bool.must_not = mustNotQueries;

    // 构建排序
    const sort: any[] = [];
    order
      .filter((item) => item.isEnable)
      .forEach((item) => {
        sort.push({ [item.field]: { order: item.type } });
      });

    // 构建搜索请求体
    const searchBody: any = {
      query: Object.keys(boolQuery.bool).length > 0 ? boolQuery : { match_all: {} },
      from: (pageNum - 1) * pageSize,
      size: pageSize
    };

    if (sort.length > 0) {
      searchBody.sort = sort;
    }

    try {
      const response = await this.request({
        method: "POST",
        url: `/${index}/_search`,
        data: JSON.stringify(searchBody)
      });

      const result = JSON.parse(response);

      return {
        total: result.hits.total.value || result.hits.total,
        data: response
      };
    } catch (error) {
      throw new Error(`搜索失败: ${error}`);
    }
  }

  seniorSearch(query: SeniorSearchProp): Promise<string> {
    return this.request({
      method: query.method,
      url: query.url,
      headers: query.headers,
      data: query.body
    });
  }
}
